﻿/* ****************************************************************************
 *
 * Copyright (c) Jeff Hardy 2007-2009.
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.txt file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * jdhardy@gmail.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * ***************************************************************************/

using System;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using Microsoft.Web.Management.Client;
using Microsoft.Web.Management.Client.Win32;
using System.Collections.Generic;

namespace NWSGI.ManagementClient
{
    internal interface INwsgiEditorForm
    {
        INwsgiConfigItem Value { get; }
    }

    internal abstract class NwsgiVariableListPage : ModuleListPage, IModuleChildPage
    {
        private IModulePage parentPage;
        public IModulePage ParentPage
        {
            get { return this.parentPage; }
            set { this.parentPage = (ModulePage)value; }
        }

        private NwsgiModuleServiceProxy _serviceProxy;
        protected NwsgiModuleServiceProxy ServiceProxy
        {
            get
            {
                if(_serviceProxy == null)
                {
                    _serviceProxy = (NwsgiModuleServiceProxy)CreateProxy(typeof(NwsgiModuleServiceProxy));
                }
                return _serviceProxy;
            }
        }

        private VariableEntryItem SelectedItem
        {
            get { return ListView.SelectedItems.Count > 0 ? (VariableEntryItem)ListView.SelectedItems[0] : null; }
        }

        private PageTaskList taskList;
        protected override TaskListCollection Tasks
        {
            get
            {
                if(this.taskList == null)
                {
                    this.taskList = new PageTaskList(this);
                }

                TaskListCollection col = base.Tasks;
                col.Add(this.taskList);
                return col;
            }
        }

        protected override bool CanRefresh
        {
            get { return !base.InProgress; }
        }

        protected virtual string[] Headers { get { return new string[] { "Name", "Value" }; } }

        protected override void InitializeListPage()
        {
            foreach(string headerTitle in Headers)
            {
                ColumnHeader header = new ColumnHeader();
                header.Text = headerTitle;
                header.Width = -2;
                ListView.Columns.Add(header);
            }

            ListView.LabelEdit = false;
            ListView.MultiSelect = false;

            ListView.ItemActivate += OnListViewItemActivate;
            ListView.SelectedIndexChanged += OnListViewSelectedIndexChanged;
            ListView.KeyUp += OnListViewKeyUp;
        }

        protected override void OnActivated(bool initialActivation)
        {
            base.OnActivated(initialActivation);
            if(initialActivation)
            {
                GetItemsAsync();
            }
        }

        protected override void Refresh()
        {
            if(CanRefresh)
                GetItemsAsync();
        }

        internal void GoBack()
        {
            base.Navigate(typeof(NwsgiPage));
        }

        private void GetItemsAsync()
        {
            StartAsyncTask("Getting variables...", new DoWorkEventHandler(GetItems),
                                                   new RunWorkerCompletedEventHandler(GetItemsCompleted));
        }

        private void GetItems(object sender, DoWorkEventArgs e)
        {
            e.Result = GetVariables();
        }

        private void GetItemsCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ListView.BeginUpdate();
            ListView.Items.Clear();
            try
            {
                IEnumerable<INwsgiConfigItem> variables = (IEnumerable<INwsgiConfigItem>)e.Result;
                foreach(INwsgiConfigItem value in variables)
                {
                    ListView.Items.Add(new VariableEntryItem(value));
                }
            }
            finally
            {
                ListView.EndUpdate();
            }
        }

        protected abstract IEnumerable<INwsgiConfigItem> GetVariables();

        private void OnListViewSelectedIndexChanged(object sender, EventArgs e)
        {
            base.Update();
        }

        private void OnListViewKeyUp(object sender, KeyEventArgs e)
        {
            if(this.SelectedItem != null && e.KeyData == Keys.Delete)
                this.DeleteItem();
        }

        private void OnListViewItemActivate(object sender, EventArgs e)
        {
            if(this.SelectedItem != null)
            {
                this.EditItem();
            }
        }

        internal void AddItem()
        {
            INwsgiEditorForm editor = GetAddItemEditor();
            
            if(((Form)editor).ShowDialog(this) == DialogResult.OK)
            {
                try
                {
                    Cursor.Current = Cursors.WaitCursor;
                    AddItem(editor.Value);
                }
                catch(Exception exception)
                {
                    base.DisplayErrorMessage("An error occurred:", exception.Message);
                }
                finally
                {
                    Cursor.Current = Cursors.Default;
                }
            }

            Refresh();
            Update();
        }

        protected virtual INwsgiEditorForm GetAddItemEditor()
        {
            return new VariableEditor(base.Module);
        }

        protected abstract void AddItem(INwsgiConfigItem value);

        internal void EditItem()
        {
            if(this.SelectedItem != null)
            {
                INwsgiEditorForm editor = GetEditItemEditor(this.SelectedItem.Backing);

                if(((Form)editor).ShowDialog(this) == DialogResult.OK)
                {
                    try
                    {
                        Cursor.Current = Cursors.WaitCursor;
                        EditItem(this.SelectedItem.Backing, editor.Value);
                    }
                    catch(Exception exception)
                    {
                        base.DisplayErrorMessage("An error occurred:", exception.Message);
                    }
                    finally
                    {
                        Cursor.Current = Cursors.Default;
                    }
                }
            }

            Refresh();
            Update();
        }

        protected virtual INwsgiEditorForm GetEditItemEditor(INwsgiConfigItem selected)
        {
            return new VariableEditor(base.Module, (VariableItem)selected.Clone(), false);
        }

        protected abstract void EditItem(INwsgiConfigItem oldValue, INwsgiConfigItem newValue);

        internal void DeleteItem()
        {
            if(this.SelectedItem != null && base.ShowMessage("Are you show you want to remove this variable?", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes)
            {
                try
                {
                    Cursor.Current = Cursors.WaitCursor;
                    DeleteItem(this.SelectedItem.Backing);
                    base.ListView.Items.Remove(this.SelectedItem);
                }
                catch(Exception exception)
                {
                    base.DisplayErrorMessage("An error occurred:", exception.Message);
                }
                finally
                {
                    Cursor.Current = Cursors.Default;
                }
            }

            Refresh();
            Update();
        }

        protected abstract void DeleteItem(INwsgiConfigItem selected);

        protected sealed class VariableEntryItem : ListViewItem
        {
            private INwsgiConfigItem backing;

            public INwsgiConfigItem Backing { get { return backing; } }

            public VariableEntryItem(INwsgiConfigItem backing)
                : base(backing.RawValues[0], 0)
            {
                this.backing = backing;

                for(int i = 1; i < backing.RawValues.Length; i++)
                {
                    SubItems.Add(new ListViewSubItem(this, backing.RawValues[i]));
                }
            }
        }

        private sealed class PageTaskList : TaskList
        {
            private NwsgiVariableListPage owner;

            public PageTaskList(NwsgiVariableListPage owner)
            {
                this.owner = owner;
            }

            public override ICollection GetTaskItems()
            {
                ArrayList list = new ArrayList();

                list.Add(new MethodTaskItem("AddItem", "Add...", "Actions", "Add a new variable"));

                ListViewItem selected = this.owner.SelectedItem;
                if(selected != null)
                {
                    list.Add(new MethodTaskItem("EditItem", "Edit", "Actions", "Edit the currently selected variable"));
                    list.Add(new MethodTaskItem("DeleteItem", "Remove", "Actions", "Delete the currently selected variable"));
                }

                list.Add(new MethodTaskItem("GoBack", "Go Back", "Tasks", "Go back to the parent page"));

                return list;
            }

            public void AddItem()
            {
                this.owner.AddItem();
            }

            public void EditItem()
            {
                this.owner.EditItem();
            }

            public void DeleteItem()
            {
                this.owner.DeleteItem();
            }

            public void GoBack()
            {
                this.owner.GoBack();
            }
        }
    }

    internal interface INwsgiConfigItem : ICloneable
    {
        string[] RawValues { get; }
    }

    internal class VariableItem : INwsgiConfigItem
    {
        public string Name { get; set; }
        public string Value { get; set; }

        public VariableItem() { }

        public VariableItem(params string[] values)
        {
            Name = values[0];
            Value = values[1];
        }

        #region INwsgiListItem Members

        public string[] RawValues
        {
            get { return new string[] { Name, Value }; }
        }

        #endregion

        #region ICloneable Members

        public object Clone()
        {
            return new VariableItem { Name = this.Name, Value = this.Value };
        }

        #endregion
    }
}
